package by.bucha.testproject.imageLoader;

import java.util.LinkedHashMap;

import android.graphics.Bitmap;

public class BitmapLruCache<K> extends LinkedHashMap<K, Bitmap> {

	/** Size in bytes */
	private int mMaxBytes;

	private static final int INITIAL_CAPACITY = 32;

	private static final float LOAD_FACTOR = 0.75f;

	private static final long serialVersionUID = 1L;

	private boolean mRemove = false;

	public BitmapLruCache(int maxBytes) {
		super(INITIAL_CAPACITY, LOAD_FACTOR, true);
		mMaxBytes = maxBytes;
	}

	private int getSize(Bitmap value) {
		int size = value.getRowBytes() * value.getHeight();
		return size;
	}

	private long sizeOf(Iterable<Bitmap> bitmaps) {
		long total = 0;
		for (Bitmap bitmap : bitmaps) {
			total += getSize(bitmap);
		}
		return total;
	}

	/**
	 * Removes additional elements until the cache is an acceptable size.
	 * <p>
	 * This method must be called after each insertion operation.
	 */
	private void trim(Bitmap value) {
		while (sizeOf(values()) > mMaxBytes) {
			trimEldest();
		}
	}

	/**
	 * Removes the eldest entry if the cache is too big.
	 */
	private void trimEldest() {
		// Remove null otherwise put() may have no effect
		super.remove(null);

		// Induce LinkedHashMap to remove the eldest element
		mRemove = true;
		try {
			super.put(null, null);
		} finally {
			mRemove = false;
		}

		// Remove null so that it does not appear in the key/entry sets
		super.remove(null);
	}

	@Override
	protected boolean removeEldestEntry(java.util.Map.Entry<K, Bitmap> eldest) {
		return mRemove;
	}

	private NullPointerException nullKeyException() {
		return new NullPointerException(
				"In LRU cache key must'n be null or empty.");
	}

	@Override
	public synchronized Bitmap put(K key, Bitmap value) {
		if (key == null || key.equals("")) {
			throw nullKeyException();
		}
		try {
			return super.put(key, value);
		} finally {
			trim(value);
		}
	}

	@Override
	public synchronized Bitmap get(Object key) {
		if (key == null) {
			throw nullKeyException();
		}
		return super.get(key);
	}

	@Override
	public synchronized boolean containsKey(Object key) {
		if (key == null) {
			throw nullKeyException();
		}
		return super.containsKey(key);
	}

	@Override
	public synchronized Bitmap remove(Object key) {
		if (key == null) {
			throw nullKeyException();
		}
		return super.remove(key);
	}
}
